package com.huanletao.tree;


import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * </p>
 * package: org.huanletao.ssm.util
 * description:
 * className: TreeUtils
 * author:  踏雪无痕
 * copyright: Copyright (c) 2022/9/4 16:21
 * since: 1.0.0
 */
public abstract class TreeUtils {

    /**
     * 通过接口构建树形结构数据
     *
     * @param treeNodes
     * @return
     */
    public static <T extends TreeNode<T>> List<T> buildTree(List<T> treeNodes) {
        List<T> treeRootNode = TreeUtils.getTreeRootNode(treeNodes);
        for (T treeNode : treeRootNode) {
            buildTree(treeNode, treeNodes);
        }
        return treeRootNode;
    }

    /**
     * @param treeNodes
     * @param treeNodeBuilder
     * @param <T>
     * @return
     */
    public static <T> List<T> buildTree(List<T> treeNodes, TreeNodeBuilder<T> treeNodeBuilder) {
        List<T> treeRootNode = TreeUtils.getTreeRootNodePlus(treeNodes, treeNodeBuilder);
        for (T treeNode : treeRootNode) {
            buildTreeChildrenPlus(treeNode, treeNodes, treeNodeBuilder);
        }
        return treeRootNode;
    }

    /**
     * @param treeNode
     * @param treeNodes
     * @param treeNodeBuilder
     * @param <T>
     */
    private static <T> void buildTreeChildrenPlus(T treeNode, List<T> treeNodes, TreeNodeBuilder<T> treeNodeBuilder) {
        List<T> nodeChildList = getTreeNodeChildListPlus(treeNode, treeNodes, treeNodeBuilder);
        //递归终止条件，
        if (nodeChildList.isEmpty()) return;
        treeNodeBuilder.setTreeChildrenNode(nodeChildList, treeNode);
        for (T treeNodec : nodeChildList) {
            buildTreeChildrenPlus(treeNodec, treeNodes, treeNodeBuilder);
        }
    }

    private static <T> List<T> getTreeNodeChildListPlus(T treeNode, List<T> treeNodes, TreeNodeBuilder<T> treeNodeBuilder) {
        return treeNodes.stream().filter(it -> treeNodeBuilder.getParentId(it).equals(treeNodeBuilder.getId(treeNode))).collect(Collectors.toList());
    }

    /**
     * @param treeNodes
     * @param treeNodeBuilder
     * @param <T>
     * @return
     */
    private static <T> List<T> getTreeRootNodePlus(List<T> treeNodes, TreeNodeBuilder<T> treeNodeBuilder) {
        return treeNodes.stream().filter(it -> treeNodeBuilder.getParentId(it).equals("0")).collect(Collectors.toList());
    }

    /**
     * @param treeNode
     * @param treeNodes
     */
    private static <T extends TreeNode<T>> void buildTree(T treeNode, List<T> treeNodes) {
        List<T> nodeChildList = getTreeNodeChildList(treeNode, treeNodes);
        //递归终止条件，
        if (nodeChildList.isEmpty()) return;
        treeNode.setTreeChildrenNode(nodeChildList);
        for (T treeNodec : nodeChildList) {
            buildTree(treeNodec, treeNodes);
        }
    }

    /**
     * @param treeNode
     * @param treeNodes
     * @return
     */
    private static <T extends TreeNode<T>> List<T> getTreeNodeChildList(T treeNode, List<T> treeNodes) {
        List<T> sysMenuList = new ArrayList<>();
        for (T treeNodec : treeNodes) {
            if (treeNodec.getParentId().equals(treeNode.getId())) {
                sysMenuList.add(treeNodec);
            }
        }
        return sysMenuList;
    }

    /**
     * @param treeNodes
     * @return
     */
    private static <T extends TreeNode<T>> List<T> getTreeRootNode(List<T> treeNodes) {
        return treeNodes.stream().filter(treeNode -> treeNode.getParentId().equals(0L)).collect(Collectors.toList());
    }


    /**
     * 通过 TreeNode<T> 接口直接打印树形结构。
     * 优化后支持 ASCII 树形风格，并兼容原有功能。
     */
    public static <T extends TreeNode<T>> void print(List<T> treeNodes) {
        List<T> rootNodes = getTreeRootNode(treeNodes);
        printRecursive(rootNodes, treeNodes, "", true);
    }

    /**
     * 递归打印树结构（基于 TreeNode<T> 接口）。
     */
    private static <T extends TreeNode<T>> void printRecursive(List<T> nodes, List<T> treeNodes, String prefix, boolean isLast) {
        if (nodes == null || nodes.isEmpty()) return;

        for (int i = 0; i < nodes.size(); i++) {
            T node = nodes.get(i);
            boolean isCurrentLast = i == nodes.size() - 1;
            String nodePrefix = isCurrentLast ? "└── " : "├── ";
            String nodeInfo = node.getNodeDisplayInfo(); // 默认使用 toString() 显示节点信息

            System.out.println(prefix + nodePrefix + nodeInfo);

            List<T> children = getTreeNodeChildList(node, treeNodes);
            String newPrefix = prefix + (isCurrentLast ? "    " : "│   ");
            printRecursive(children, treeNodes, newPrefix, isCurrentLast);
        }
    }

    /**
     * 通过 TreeNodeBuilder 构建并打印树形结构。
     *
     * @param treeNodes       节点集合
     * @param treeNodeBuilder 用于构建树的辅助接口
     */
    public static <T> void printWithBuilder(List<T> treeNodes, TreeNodeBuilder<T> treeNodeBuilder) {
        List<T> rootNodes = getTreeRootNodePlus(treeNodes, treeNodeBuilder);
        printWithBuilderRecursive(rootNodes, treeNodes, treeNodeBuilder, "", " ");
    }

    /**
     * 递归打印树结构（基于 TreeNodeBuilder）。
     */
    private static <T> void printWithBuilderRecursive(List<T> nodes, List<T> treeNodes, TreeNodeBuilder<T> builder, String prefix, String indent) {
        if (nodes == null || nodes.isEmpty()) return;

        for (int i = 0; i < nodes.size(); i++) {
            T node = nodes.get(i);
            boolean isLast = i == nodes.size() - 1;
            String nodePrefix = isLast ? "└── " : "├── ";
            String nodeInfo = builder.getNodeDisplayInfo(node); // 获取节点显示信息（如 ID 或名称）

            System.out.println(prefix + nodePrefix + nodeInfo);

            // 获取子节点
            List<T> children = getTreeNodeChildListPlus(node, treeNodes, builder);
            String newPrefix = prefix + (isLast ? "    " : "│   ");
            printWithBuilderRecursive(children, treeNodes, builder, newPrefix, indent);
        }
    }


}
